/********************************************************************** 
 * FILE		: FileUtilTools.java					
 *			
 * AUTHOR   : kloyf		
 * 
 * DATE		: 2011-6-3
 * 									
 * REASON	: CREATE  
 *            							
 * VERSION  ：0.0.1
 *
 ***********************************************************************/
package com.common.util.file;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import com.common.util.date.DateFormat;
import com.common.util.date.DateUtilTools;

/**
 * 文件操作工具类
 * 
 * @author kloyf
 * @version 0.0.1
 * 
 */
public class FileUtilTools extends AbstractFileUtil {
	private static Class clazz = FileUtilTools.class;

	/**
	 * <pre>
	 * 获得绝对路径
	 * </pre>
	 * 
	 * @return String 绝对项目的路径
	 */
	public static String getPath() {
		return Thread.currentThread().getContextClassLoader().getResource("").getPath();

	}

	/**
	 * <pre>
	 * 取得某个目录下的所有文件和目录。
	 * </pre>
	 * 
	 * @param path
	 *            文件夹路径
	 * @return Map<文件名,类型> 返回文件和目录名及对应的类型
	 */
	public static Map<String, String> getFilesAndDirectores(String path) {
		File file = getFile(path);
		if (file.isFile())
			return new HashMap<String, String>();

		Map<String, String> fileMap = new HashMap<String, String>();

		File[] files = file.listFiles();

		for (File tempFile : files) {
			if (tempFile.isFile())
				fileMap.put(tempFile.getName(), FilenameUtils.getExtension(tempFile.getName()));
			if (tempFile.isDirectory())
				fileMap.put(path + tempFile.getName(), "dir");
		}
		return fileMap;
	}

	/**
	 * <pre>
	 * 取得某个文件夹下的文件。
	 * </pre>
	 * 
	 * @param path
	 *            文件夹路径
	 * @return Map<文件名,类型> 返回文件和目录名及对应的类型
	 */
	public static Map<String, String> getFiles(String path) {

		File file = getFile(path);
		if (file.isFile())
			return new HashMap<String, String>();
		Map<String, String> fileMap = new HashMap<String, String>();
		File[] files = file.listFiles();
		for (File tempFile : files) {
			if (tempFile.isFile())
				fileMap.put(tempFile.getName(), FilenameUtils.getExtension(tempFile.getName()));
		}
		return fileMap;
	}

	/**
	 * 判断一个文件是否存在
	 * 
	 * @param path
	 *            文件路径
	 * @return 存在返回true，否则返回false
	 */
	public static boolean isExist(String path) {
		try {
			return getFile(path).exists();
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 根据文件类型选择文件。
	 * 
	 * @param path
	 *            文件路径
	 * @param type
	 *            文件类型
	 * @return Map<文件名,类型> 返回文件和目录名及对应的类型
	 */
	public static Map<String, String> getFilesByType(String path, String type) {
		File file = getFile(path);
		if (file.isFile())
			return new HashMap<String, String>();
		Map<String, String> fileMap = new HashMap<String, String>();
		File[] files = file.listFiles();

		for (File tempFile : files) {
			if (tempFile.isFile() && FilenameUtils.getExtension(tempFile.getName()).equals(type))
				fileMap.put(tempFile.getName(), FilenameUtils.getExtension(tempFile.getName()));
		}
		return fileMap;
	}

	/**
	 * 取得文件夹下的目录。
	 * 
	 * @param path
	 *            文件路径
	 * @return List<目录名> 返回目录名List
	 */
	public static List<String> getDirectores(String path) {
		File file = new File(path);
		if (file.isFile())
			return new ArrayList<String>();
		List<String> fileList = new ArrayList<String>();
		File[] files = file.listFiles();
		for (File tempFile : files) {
			if (tempFile.isDirectory())
				fileList.add(path + tempFile.getName());
		}
		return fileList;
	}

	/**
	 * 取得文件夹下的文件类型。
	 * 
	 * @param path
	 *            文件路径
	 * @return Set<文件类型> 返回文件类型SET
	 */
	public static Set<String> getFileType(String path) {
		File file = new File(path);
		if (file.isFile())
			return new HashSet<String>();
		Set<String> fileTypeSet = new HashSet<String>();
		File[] files = file.listFiles();
		for (File tempFile : files) {
			if (tempFile.isFile())
				fileTypeSet.add(FilenameUtils.getExtension(tempFile.getName()));
		}
		return fileTypeSet;
	}

	/**
	 * 改文件名或者文件夹的名字。
	 * 
	 * @param path
	 *            文件路径
	 * @param oldName
	 *            旧文件名
	 * @param newName
	 *            新文件名
	 * @return boolean 返回boolean。成功返回true，错误返回false
	 */
	public static boolean reName(String path, String oldName, String newName) {
		return getFile(path + oldName).renameTo(getFile(path + newName));
	}

	/**
	 * 把目录拷贝到目录中。
	 * 
	 * @param refDir
	 *            原始目录
	 * @param tarDir
	 *            目标目录
	 * @return boolean 返回boolean。成功返回true，错误返回false
	 */
	public static boolean copyDirectoryToDirectory(String refDir, String tarDir) {
		try {
			FileUtils.copyDirectoryToDirectory(getFile(refDir), getFile(tarDir));
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 把目录移动到目录中。
	 * 
	 * @param refDir
	 *            源目录
	 * @param tarDir
	 *            目标目录
	 * @return boolean 返回boolean。成功返回true，错误返回false
	 */
	public static boolean moveDirectoryToDirectory(String refDir, String tarDir) {
		try {
			FileUtils.moveDirectoryToDirectory(getFile(refDir), new File(tarDir), true);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * <pre>
	 * 删除文件夹
	 * </pre>
	 * 
	 * @param path
	 *            文件夹路径
	 */
	public static boolean deleteDirectory(String path) {
		// 如果path不以文件分隔符结尾，自动添加文件分隔符
		if (!path.endsWith(File.separator)) {
			path = path + File.separator;
		}
		File file = getFile(path);
		// 如果dir对应的文件存在，或者是一个目录，则删除。否则输出错误提示。
		if (file.exists() || file.isDirectory()) {
			File[] files = file.listFiles();
			for (int i = 0; i < files.length; i++) {
				if (files[i].isFile()) {
					deleteFile(files[i].getAbsolutePath());
				} else {
					deleteDirectory(files[i].getAbsolutePath());
				}
			}
			file.delete();
			return true;
		} else {
			debug(clazz, "");
			return false;
		}

	}

	/**
	 * <pre>
	 * 功能描述：将已经生成的文件按行读取到一个List里。以便进行修改。
	 * </pre>
	 * 
	 * @param path
	 *            文件绝对路径
	 * @return 返回生成的文件List。
	 */
	public static List<String> readerFile(String path) {
		BufferedReader br = null;
		List<String> lineList = new ArrayList<String>();
		try {
			br = new BufferedReader(new FileReader(path));
			String temp = null;
			// 将文件一行行读取到list里。
			while ((temp = br.readLine()) != null) {
				StringBuffer sb = new StringBuffer(4096);
				sb.append(temp).append("\r\n");
				lineList.add(sb.toString());
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return lineList;
	}

	/**
	 * 返回文件夹的大小，b返回字节数，k以k为单位,m以m为单位。
	 * 
	 * @param path
	 *            文件夹URL
	 * @param type
	 *            返回大小的单位。
	 * @return long 文件夹下所有文件的大小。
	 */
	public static long sizeOfDirectory(String path, char type) {
		long size = FileUtils.sizeOfDirectory(new File(path));

		switch (type) {
		case 'b':
			return size;
		case 'k':
			return size / 1024;
		case 'm':
			return size / (1024 * 1024);
		default:
			return size;
		}
	}

	/**
	 * <pre>
	 * 删除文件
	 * </pre>
	 * 
	 * @param path
	 *            文件路径
	 */
	public static boolean deleteFile(String path) {
		// 如果path不以文件分隔符结尾，自动添加文件分隔符
		if (!path.endsWith(File.separator)) {
			path = path + File.separator;
		}
		try {
			getFile(path).delete();
			return true;
		} catch (Exception e) {
			// TODO: handle exception
			return false;
		}
	}

	/**
	 * 拷贝文件到一个新位置。
	 * 
	 * @param srcFile
	 *            源文件URL
	 * @param tarFile
	 *            目标URL
	 * @param changeDate
	 * @return boolean 返回boolean。成功返回true，错误返回false
	 */
	public static boolean copyFile(String srcFile, String tarFile, boolean changeDate) {
		try {
			FileUtils.copyFile(new File(srcFile), new File(tarFile), changeDate);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 移动文件。
	 * 
	 * @param srcFile
	 *            源文件URL
	 * @param tarFile
	 *            目标文件URL
	 * @return boolean 返回boolean。成功返回true，错误返回false
	 */
	public static boolean moveFile(String srcFile, String tarFile) {
		try {
			FileUtils.moveFile(new File(srcFile), new File(tarFile));
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 把文件拷贝到某个文件夹下。
	 * 
	 * @param srcFile
	 *            源文件URL
	 * @param tarDir
	 *            目标URL
	 * @param changeDate
	 * @return boolean 返回boolean。成功返回true，错误返回false
	 */
	public static boolean copyFileToDirectory(String path, String srcFile, String tarDir, boolean changeDate) {
		try {
			FileUtils.copyFileToDirectory(new File(path + srcFile), new File(tarDir), changeDate);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 把多个文件拷贝到某个文件夹下。
	 * 
	 * @param path
	 *            文件路径URL
	 * @param srcFiles
	 *            源文件URL数组
	 * @param tarDir
	 *            目标URL
	 * @param changeDate
	 * @return boolean 返回boolean。成功返回true，错误返回false
	 */
	public static boolean copyFilesToDirectory(String path, String[] srcFiles, String tarDir, boolean changeDate) {
		try {
			for (String srcFile : srcFiles)
				FileUtils.copyFileToDirectory(new File(path + srcFile), new File(tarDir), changeDate);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 移动文件到文件夹下。
	 * 
	 * @param path
	 *            文件路径URL
	 * @param srcFile
	 *            源文件名
	 * @param tarDir
	 *            目标文件夹URL
	 * @param changeDate
	 * @return boolean 返回boolean。成功返回true，错误返回false
	 */
	public static boolean moveFileToDirectory(String path, String srcFile, String tarDir, boolean changeDate) {
		try {
			FileUtils.moveFileToDirectory(new File(path + srcFile), new File(tarDir), changeDate);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 移动多个文件到文件夹下。
	 * 
	 * @param path
	 *            文件路径URL
	 * @param srcFiles
	 *            源文件名数组
	 * @param tarDir
	 *            目标文件URL
	 * @param changeDate
	 * @return boolean 返回boolean。成功返回true，错误返回false
	 */
	public static boolean moveFilesToDirectory(String path, String[] srcFiles, String tarDir, boolean changeDate) {
		try {
			for (String srcFile : srcFiles)
				FileUtils.moveFileToDirectory(new File(path + srcFile), new File(tarDir), changeDate);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 拷贝远程的文件到本地，需要传入远程的url。
	 * 
	 * @param url
	 *            远程文件URL
	 * @param path
	 *            目标URL
	 * @return boolean 返回boolean。成功返回true，错误返回false
	 */
	public static boolean copyRemoteFileToLocal(String url, String path) {
		try {
			FileUtils.copyURLToFile(new URL(url), getFile(path));
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 以字符为单位读取文件，常用于读文本，数字等类型的文件
	 */
	public static String readFileByChars(String path) {
		File file = getFile(path);
		Reader reader = null;
		StringBuffer outBuffer = new StringBuffer();
		try {
			// 一次读多个字符
			char[] tempchars = new char[30];
			int charread = 0;
			reader = new InputStreamReader(new FileInputStream(path), "UTF-8");
			// 读入多个字符到字符数组中，charread为一次读取字符数
			while ((charread = reader.read(tempchars)) != -1) {
				for (int i = 0; i < charread; i++) {
					outBuffer.append(tempchars[i]);
				}
			}

		} catch (Exception e1) {
			e1.printStackTrace();
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e1) {
				}
			}
		}
		return outBuffer.toString();
	}

	/**
	 * <pre>
	 * 创建一个文件夹
	 * </pre>
	 * 
	 * @param path
	 *            文件夹路径
	 */
	public static void makeDirectory(String path) {
		// 如果path不以文件分隔符结尾，自动添加文件分隔符
		if (!path.endsWith(File.separator)) {
			path = path + File.separator;
		}
		getFile(path).mkdir();
	}

	/**
	 * <pre>
	 * 判断一个绝对路径下，是否有这个文件。如果没有，则会创建完整路径，并且创建这个文件。
	 * </pre>
	 * 
	 * @param path
	 *            文件的绝对路径
	 */
	public static void createFile(String path) {
		File file = new File(path);
		if (!FileUtilTools.isExist(path)) {
			file.getParentFile().mkdirs();
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * <pre>
	 * 输出一个字符流文件。</br>
	 * 根据绝对路径，输出一个字符文件。
	 * </pre>
	 * 
	 * @param path
	 *            文件的绝对路径。
	 * @param content
	 *            文件的内容。
	 * @param add
	 *            是否对文件内容进行追加。如果是则为true，否则为false。
	 */
	public static void outFileWriter(String path, String content, boolean add) {
		FileWriter fileWriter = null;
		if (!FileUtilTools.isExist(path)) {
			FileUtilTools.createFile(path);
		}
		try {
			fileWriter = new FileWriter(new File(path), add);
			fileWriter.write(content);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			closeStream(fileWriter);
		}

	}

	/**
	 * <pre>
	 * 将一个数据结果集输出为一个EXCEL文件<br>
	 * 结果集采用List<Map<String, Object>>数据结构。<br>
	 * 
	 * @param list
	 *            List<Map<String, Object>> 需要生成EXCEL的数据结果集
	 * @param filePath
	 *            String 输出的文件路径+文件名
	 * 
	 * </pre>
	 */
	public static void outPutExcel(List<Map<String, Object>> list, String filePath) {
		HSSFWorkbook workbook = getWorkbook();
		HSSFSheet sheet = workbook.createSheet();
		int rowIndex = 0;
		for (Map<String, Object> node : list) {
			HSSFRow row = sheet.createRow(rowIndex++);
			Iterator<String> it = node.keySet().iterator();
			int cellIndex = 0;
			while (it.hasNext()) {
				String keyString = it.next();
				HSSFCell cell = row.createCell(cellIndex++);
				if (node.get(keyString) instanceof Date) {
					cell.setCellValue(DateUtilTools.formatDate((Date) node.get(keyString), DateFormat.DATE_FORMAT_NUM1.getValue()));
				}
				if (node.get(keyString) instanceof Integer) {
					cell.setCellValue((Integer) node.get(keyString));
				}
				if (node.get(keyString) instanceof String) {
					cell.setCellValue((String) node.get(keyString));
				}
				if (node.get(keyString) instanceof Float) {
					cell.setCellValue((Float) node.get(keyString));
				}
				if (node.get(keyString) instanceof Double) {
					cell.setCellValue((Double) node.get(keyString));
				}
				if (node.get(keyString) instanceof Boolean) {
					cell.setCellValue((Boolean) node.get(keyString));
				}
				cell.setCellType(HSSFCell.CELL_TYPE_STRING);// 设置单元格数据类型
			}
		}
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(filePath);
			workbook.write(fos);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
